import wx 
import ogre.renderer.OGRE as ogre 
try : 
	import psyco #use psyco if available (JIT compiler) 
	psyco.full() 
except ImportError: 
	pass 

def getPluginPath():
	"""Return the absolute path to a valid plugins.cfg file.""" 
	import sys
	import os
	import os.path

	paths = [os.path.join(os.getcwd(), 'ogre_plugins.cfg'),
			 '/etc/OGRE/ogre_plugins.cfg',
			 os.path.join(os.path.dirname(os.path.abspath(__file__)),
							  'ogre_plugins.cfg')]
	for path in paths:
		if os.path.exists(path):
			return path

	sys.stderr.write("\n"
		"** Warning: Unable to locate a suitable plugins.cfg file.\n"
		"** Warning: Please check your ogre installation and copy a\n"
		"** Warning: working plugins.cfg file to the current directory.\n\n")
	raise ogre.Exception(0, "can't locate the 'ogre_plugins.cfg' file", "")

class Struct: 
	"simple dummy class to regroup scene entities in a single parameter" 
	pass 

class OgreWindow(wx.PyWindow): 
	"""wx.Frame subclass to embed an Ogre window in wxPython 
	It is somewhat inspired from SampleFramework.py""" 

	#all animation states included in this dictionary will be automatically updated at each render 
	animStates = {} #the values have to be (AnimationState, SpeedFactor) tuples 

	#namespace for holding a reference to the entities you create. You can comment it out 
	#if you don't like the idea 
	#sceneEntities = Struct() 

	def __init__(self, parent, ID, size = wx.Size(640,480), renderSystem = "OpenGL",**kwargs): 
		self.parent=parent 
		wx.PyWindow.__init__(self, parent, ID, size = size, **kwargs) 
		#Event bindings 
		self.Bind(wx.EVT_CLOSE, self._OnCloseWindow) 
		self.Bind(wx.EVT_ERASE_BACKGROUND, self._OnEraseBackground) 
		self.Bind(wx.EVT_SIZE, self._OnSize) 
		self.Bind(wx.EVT_TIMER, self.UpdateRender) #Bind the timer events to Ogre rendering 
		#Timer creation 
		self.timer = wx.Timer() 
		self.timer.SetOwner(self) #Sets the timer to notify self: binding the timer event is not enough 

		#Ogre Initialisation 
		self._OgreInit(size,renderSystem) 
		self.SceneInitialisation() 
		self.UpdateRender() 
		self.SetFocus()#Gives KeyboardFocus 

	def _OgreInit(self,size,renderSystem):	
		#Root creation 
		root = ogre.Root(getPluginPath()) 
		self.ogreRoot = root 

		# setup resources 
		config = ogre.ConfigFile() 
#		 config.loadFromFile('resources.cfg') 
#		 for section, key, path in config.values: 
#			 ogre.ResourceGroupManager.getSingleton().addResourceLocation(path, key, section)  

		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/packs/OgreCore.zip", "Zip", "Bootstrap", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/fonts", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/materials/programs", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/materials/scripts", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/materials/textures", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/models", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/overlays", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/particle", "FileSystem", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/packs/cubemap.zip", "Zip", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/packs/cubemapsJS.zip", "Zip", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/packs/dragon.zip", "Zip", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/packs/fresneldemo.zip", "Zip", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/packs/ogretestmap.zip", "Zip", "General", False)
#		ogre.ResourceGroupManager.getSingleton().addResourceLocation("media/packs/skybox.zip", "Zip", "General", False)

		#The following section tries to avoid showing the configuration dilaog. 
#		 rsList = root.getAvailableRenderers() #Gets the available RenderSystems 
#		 rs=None 
#		 CouldNotFindRequestedRenderer=False 
#		 for i in rsList: 
#			 if renderSystem in i.name: #Tries to locate the requested render system 
#				 rs=i 
#		 if rs is not None : 
#			 root.renderSystem=rs 
#			 rs.setConfigOption("Full Screen","No") 
#			 try : 
#				 rs.setConfigOption("Video Mode","800 x 600 @ 16-bit colour") 
#			 except : 
#				 CouldNotFindRequestedRenderer=True 
#		 else : 
#			 CouldNotFindRequestedRenderer=True 
#			 
#		 if CouldNotFindRequestedRenderer:	#Calls Ogre's default Config dialog if failed 
#			 carryOn = root.showConfigDialog() 
#			 if not carryOn: 
#				 sys.exit('Quit from Config Dialog') 
		carryOn = root.showConfigDialog() 
		if not carryOn: 
			import sys
			sys.exit('Quit from Config Dialog') 


		root.initialise(False) 

		renderParameters = ogre.NameValuePairList() 
		renderParameters['externalWindowHandle'] = str(self.GetHandle()) 
		renderWindow = root.createRenderWindow('wxPython render window', size[0], 
											   size[1], False, renderParameters) 
		renderWindow.active = True 
		self.renderWindow = renderWindow 
		ogre.ResourceGroupManager.getSingleton().initialiseAllResourceGroups() 



	def _OnSize(self, event): 
		if getattr(self, 'renderWindow', None): 
			self.UpdateRender() 
			self.renderWindow.windowMovedOrResized() 
		event.Skip() 

	def _OnEraseBackground(self, event): 
		pass # Do nothing, to avoid flashing on MSW. 

	def _OnCloseWindow(self, event): 
		self.Destroy() 

	def AcceptsFocus(self): 
		return True 

	def StartRendering(self,interval=33): 
		"Activates the timer. A rendering will be triggered at each interval (default :33ms)" 
		self.timer.Start(interval) 

	def OnFrameStarted(self,event): 
		"SubClass and fill in this declaration if you want something done before each rendering" 
		pass 

	def OnFrameEnded(self,event): 
		"SubClass and fill in this declaration if you want something done after each rendering" 
		pass 

	def UpdateRender(self,event=None): 
		"""Method that can be called manually or by a wx.Timer 
		If the method is called by timer, the animation states contained in 
		the self.animStates variable get updated before rendering the frame""" 

		#Enables the user to define actions to be undertaken before the frame is started 
		self.OnFrameStarted(event)		

		if hasattr(event ,"GetInterval"): #Timer Events have a GetInterval method that returns the time interval between events 
			for anim,speed in self.animStates.itervalues(): 
				anim.addTime(speed*event.GetInterval()/1000.0) #updates the animations 

		self.ogreRoot.renderOneFrame()#Asks Ogre to render a frame 

		#Enables the user to define actions to be undertaken after the frame has been drawn 
		self.OnFrameEnded(event) 

	def SceneInitialisation(self): 
		"""This method can be replaced completely to suit your needs or you can 
		subclass only the helper methods such as self._CreateCamera""" 
		self._ChooseSceneManager()
		self._MouseAndKeysBindings()

	#You will want to subclass the following methods to suit your needs	

	def _ChooseSceneManager(self): 
		"choose SceneManager" 
		self.sceneManager = self.ogreRoot.createSceneManager(ogre.ST_GENERIC,"EditorSMInstance")
		pass

	def getSceneManager(self):
		return self.sceneManager
	
	def addKeyDownListener(self,l): 
		self.KeyDownListeners.append(l)
		pass

	def addKeyUpListener(self,l): 
		self.KeyUpListeners.append(l)
		pass

	def addMouseListener(self,l): 
		self.MouseListeners.append(l)
		pass

	def removeKeyDownListener(self,l): 
		self.KeyDownListeners.remove(l)
		pass

	def removeKeyUpListener(self,l): 
		self.KeyUpListeners.remove(l)
		pass

	def removeMouseListener(self,l): 
		self.MouseListeners.remove(l)
		pass

	#
	def _MouseAndKeysBindings(self): 
		"Some Additional mouse and keys bindings" 
		self.Bind(wx.EVT_KEY_DOWN,self._KeyDownEventListener) 
		self.Bind(wx.EVT_KEY_UP,self._KeyUpEventListener) 
		##self.Bind(wx.EVT_ENTER_WINDOW,lambda evt : self.SetFocus()) 
		self.Bind(wx.EVT_MOUSE_EVENTS,self._MouseEventListener)

		self.KeyDownListeners = []
		self.KeyUpListeners = []
		self.MouseListeners = []
		pass

	def _KeyDownEventListener(self,event): 
		for l in self.KeyDownListeners:
			l(event)
			if event.GetSkipped() :
				return
		pass

	def _KeyUpEventListener(self,event): 
		for l in self.KeyUpListeners:
			l(event)
			if event.GetSkipped() :
				return
		pass

	def _MouseEventListener(self, event): 
		
		if event.RightDown() :
			self.SetFocus() #Gives Keyboard focus to the window 

		for l in self.MouseListeners:
			l(event)
			if event.GetSkipped() :
				return
		pass

	def IClearScene(self):
		self.getSceneManager().clearScene()
		self.getSceneManager().setFog()
		pass








